Módulos Essenciais de Python

    Luciano Magalhães Luciano Magalhães    Agosto, 2024 Ciência de Dados


A ciência de dados abrange um conjunto diversificado de técnicas e ferramentas que permitem a extração de conhecimento e insights valiosos a partir de dados. Python, com sua vasta coleção de bibliotecas, é uma escolha popular para cientistas de dados. Além dos módulos comuns como NumPy, Pandas, Matplotlib e Scikit-learn, existem outros módulos que podem ser utilizados para análises mais avançadas e específicas.

Neste artigo apresento alguns módulos adicionais para ciência de dados utilizando o conjunto de dados House Prices do Kaggle. Esses módulos incluem:

Dask: Para manipulação e análise de dados em grande escala.
XGBoost: Para modelos de gradient boosting.
SHAP: Para interpretar modelos de machine learning.
Plotly: Para visualizações interativas.
TensorFlow: Para deep learning.

In [1]:
# suprimir avisos (warnings)
import warnings
warnings.filterwarnings("ignore")

1. Dask: Manipulação e Análise de Dados em Grande Escala

Quando lidamos com grandes volumes de dados, o Pandas pode não dar conta do recado, especialmente quando a memória é limitada. É aqui que o Dask entra em cena. Imagine dividir seu conjunto de dados em blocos menores e trabalhar com eles como se fosse o Pandas, mas com uma vantagem: o Dask distribui esse trabalho em vários núcleos do seu processador, ou até em diferentes máquinas. Isso significa que você pode processar grandes bases de dados sem se preocupar com a falta de memória.

Exemplo:

No exemplo abaixo, usamos o Dask para carregar e analisar um conjunto de dados de forma eficiente, mostrando como ele calcula estatísticas descritivas rapidamente, mesmo com grandes volumes de informação:

In [2]:
import dask.dataframe as dd

# URL do conjunto de dados
url = "https://raw.githubusercontent.com/ageron/handson-ml/master/datasets/housing/housing.csv"

# Carregando o conjunto de dados usando Dask
dados_casas_dask = dd.read_csv(url)

# Calculando estatísticas descritivas
descricao_dask = dados_casas_dask.describe()

# executa operações de forma eficiente em grandes conjuntos de dados
descricao_dask_computed = descricao_dask.compute()

# Exibindo o resultado das estatísticas descritivas
print(descricao_dask_computed)
          longitude      latitude  housing_median_age   total_rooms  \
count  20640.000000  20640.000000        20640.000000  20640.000000   
mean    -119.569704     35.631861           28.639486   2635.763081   
std        2.003532      2.135952           12.585558   2181.615252   
min     -124.350000     32.540000            1.000000      2.000000   
25%     -121.800000     33.930000           18.000000   1447.750000   
50%     -118.490000     34.260000           29.000000   2127.000000   
75%     -118.010000     37.710000           37.000000   3148.000000   
max     -114.310000     41.950000           52.000000  39320.000000   

       total_bedrooms    population    households  median_income  \
count    20433.000000  20640.000000  20640.000000   20640.000000   
mean       537.870553   1425.476744    499.539680       3.870671   
std        421.385070   1132.462122    382.329753       1.899822   
min          1.000000      3.000000      1.000000       0.499900   
25%        296.000000    787.000000    280.000000       2.563400   
50%        435.000000   1166.000000    409.000000       3.534800   
75%        647.000000   1725.000000    605.000000       4.743250   
max       6445.000000  35682.000000   6082.000000      15.000100   

       median_house_value  
count        20640.000000  
mean        206855.816909  
std         115395.615874  
min          14999.000000  
25%         119600.000000  
50%         179700.000000  
75%         264725.000000  
max         500001.000000  

Utilizando o método compute() em Dask, as operações que foram configuradas de forma paralela são executadas e o resultado é coletado. Isso difere do Pandas, onde todas as operações são realizadas de forma sequencial e em um único núcleo. O Dask, portanto, é ideal para cenários em que o tempo de processamento e a capacidade de memória são críticos, como em grandes bases de dados corporativas.

Benefícios Adicionais:

Dask também é altamente compatível com outras bibliotecas do ecossistema Python, como NumPy e Scikit-learn, facilitando a integração em pipelines de dados já existentes. Além disso, sua capacidade de escalar de um laptop para um cluster distribuído sem alterar o código subjacente o torna uma ferramenta flexível e poderosa para cientistas de dados.

Ao usar o Dask, você aproveita melhor os recursos do seu computador, garantindo que as análises sejam feitas de maneira eficiente, sem comprometer a performance, mesmo com grandes quantidades de dados.


2. XGBoost: Modelos de Gradient Boosting¶

Gradient Boosting é uma técnica que combina o aprendizado sequencial de modelos fracos, geralmente árvores de decisão, para construir um modelo forte. No XGBoost, cada árvore é treinada para corrigir os erros do conjunto anterior, e as previsões são ajustadas iterativamente. A importância dessa abordagem é que ela minimiza o erro ao longo das iterações, resultando em um modelo final que é uma combinação ponderada de todas as árvores. Isso o torna altamente eficaz para tarefas como regressão e classificação, especialmente em conjuntos de dados com ruído e outliers.

In [6]:
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import pandas as pd

# Carregando o conjunto de dados usando pandas
dados_casas = pd.read_csv(url)

# Preparando os dados
X = dados_casas[["total_rooms"]]
y = dados_casas["median_house_value"]
X_treino, X_teste, y_treino, y_teste = train_test_split(X, y, test_size=0.3, random_state=42)

# Treinando um modelo XGBoost
modelo_xgb = xgb.XGBRegressor(objective ='reg:squarederror', n_estimators=100)
modelo_xgb.fit(X_treino, y_treino)

# Faz previsões
y_pred_xgb = modelo_xgb.predict(X_teste)

# Avaliando o modelo
rmse = mean_squared_error(y_teste, y_pred_xgb, squared=False)
print("RMSE do Modelo XGBoost:", rmse)
RMSE do Modelo XGBoost: 113329.45682157896

Gradient Boosting é uma técnica utilizada para melhorar a precisão de modelos preditivos combinando vários modelos simples, como árvores de decisão. No XGBoost, cada árvore é treinada para corrigir os erros das previsões anteriores, resultando em um modelo final que é uma soma ponderada de todas as árvores. Essa metodologia é eficaz para lidar com dados complexos, onde ruídos e outliers podem dificultar a precisão das previsões.

Ao aplicar o XGBoost, é fundamental ajustar os hiperparâmetros, como a profundidade das árvores (max_depth), a taxa de aprendizado (learning_rate), e o número de iterações (n_estimators). Esses ajustes garantem que o modelo não apenas capture as nuances dos dados, mas também evite o overfitting, mantendo a capacidade de generalização para novos dados.

No código apresentado, o modelo inicial alcançou um RMSE de aproximadamente 113329.46, sugerindo uma boa precisão inicial. No entanto, há espaço para otimização, e no próximo passo, utilizaremos o GridSearchCV para refinar esses hiperparâmetros e melhorar ainda mais o desempenho do modelo.

In [9]:
from sklearn.model_selection import GridSearchCV

# Defini os hiperparâmetros que serão otimizados
param_grid = {
    'learning_rate': [0.01, 0.1, 0.2],# Taxa de aprendizado, controla o quanto cada nova árvore contribui para corrigir os erros das árvores anteriores
    'max_depth': [3, 5, 7],           # Profundidade máxima das árvores, controlando a complexidade do modelo
    'subsample': [0.6, 0.8, 1.0],     # Fração das amostras usadas para treinar cada árvore. Usar menos de 1.0 (100%) ajuda a prevenir overfitting
    'n_estimators': [100, 200, 300]   # Número de árvores a serem construídas no modelo, controlando o número de iterações
}

# Instancia o modelo XGBoost
modelo_xgb = xgb.XGBRegressor(objective='reg:squarederror', random_state=42)

# Configura o GridSearchCV / validação cruzada com 5 divisões, e critério de avaliação será o erro quadrático médio negativo - scoring
grid_search = GridSearchCV(estimator=modelo_xgb, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error', verbose=1)

# Executa a busca pelos melhores hiperparâmetros
grid_search.fit(X_treino, y_treino)

# Exibi os melhores parâmetros encontrados
print("Melhores Hiperparâmetros:", grid_search.best_params_)

# Treina o modelo com os melhores parâmetros
modelo_otimizado = grid_search.best_estimator_

# Faz previsões e avalia o modelo otimizado
y_pred_otimizado = modelo_otimizado.predict(X_teste)
rmse_otimizado = mean_squared_error(y_teste, y_pred_otimizado, squared=False)
print("RMSE do Modelo Otimizado:", rmse_otimizado)
Fitting 5 folds for each of 81 candidates, totalling 405 fits
Melhores Hiperparâmetros: {'learning_rate': 0.01, 'max_depth': 3, 'n_estimators': 200, 'subsample': 0.6}
RMSE do Modelo Otimizado: 112555.30074019264

Após a execução do GridSearchCV, o modelo XGBoost foi ajustado com os melhores hiperparâmetros encontrados: learning_rate: 0.01, max_depth: 3, n_estimators: 200, subsample: 0.6. Esses ajustes foram fundamentais para melhorar a performance do modelo, resultando em um RMSE de 112555.30. Esse processo de otimização é essencial para garantir previsões mais precisas, refinando o modelo para melhor atender às especificidades do conjunto de dados e das tarefas de previsão.


3. SHAP: Interpretação de Modelos de Machine Learning¶

SHAP (SHapley Additive exPlanations) é uma biblioteca que fornece explicações interpretáveis para os resultados de modelos de machine learning.

In [12]:
import shap

# Criaando um objeto Explainer
explainer = shap.Explainer(modelo_otimizado, X_treino)
shap_values = explainer(X_teste)

# Visualizando os valores SHAP
shap.summary_plot(shap_values, X_teste)
 94%|=================== | 5818/6192 [00:11<00:00]       
No description has been provided for this image

SHAP (SHapley Additive exPlanations) é uma poderosa ferramenta que facilita a interpretação de modelos complexos de machine learning. Em nosso exemplo, utilizamos SHAP para analisar o modelo XGBoost, e os valores SHAP nos ajudam a entender a contribuição de cada variável para as previsões do modelo.

No gráfico de dispersão SHAP, usando o modelo otimisado, cada ponto representa uma previsão individual. A cor dos pontos indica o valor da variável total_rooms, variando de azul (valores baixos) a rosa (valores altos). A posição no eixo x revela o impacto dessa variável nas previsões: pontos à direita (impacto positivo) indicam que valores mais altos de total_rooms tendem a aumentar a previsão do valor da casa, enquanto pontos à esquerda (impacto negativo) sugerem o contrário.

Essa visualização é crucial para entender como o modelo XGBoost está utilizando a variável total_rooms para fazer previsões, além de permitir a identificação de padrões ou possíveis outliers que podem estar influenciando as previsões de maneira inesperada.


4. Plotly: Visualizações Interativas¶

In [13]:
import plotly.express as px

# Carregando o conjunto de dados usando pandas
dados_casas = pd.read_csv(url)

# Criando um gráfico de dispersão interativo
fig = px.scatter(dados_casas, x="total_rooms", y="median_house_value", title="Área da Casa vs. Preço")
fig.show()

No exemplo acima, utilizamos plotly.express para criar um gráfico de dispersão interativo que revela a relação entre o número total de cômodos (total_rooms) e o valor mediano das casas (median_house_value). Cada ponto no gráfico representa uma casa específica, onde a posição ao longo do eixo x corresponde ao número total de cômodos, enquanto a posição ao longo do eixo y reflete o preço mediano da casa.

A análise visual desse gráfico sugere que, em geral, há uma correlação positiva entre o tamanho da casa (medido pelo número de cômodos) e o valor mediano da casa. No entanto, é importante observar a distribuição dos dados, a presença de outliers e a variação dos valores. Esses elementos podem indicar situações em que a relação esperada não se mantém, possivelmente devido a outros fatores influenciando o preço das casas, como localização ou condição da propriedade.

Além disso, essa visualização interativa permite ao analista explorar os dados de maneira dinâmica, filtrando e focando em subgrupos específicos de casas, o que pode revelar padrões ou insights adicionais que não seriam imediatamente visíveis em uma análise estática.


5. TensorFlow: Deep Learning¶

In [14]:
import tensorflow as tfqq
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense


# Carregando o conjunto de dados usando pandas
dados_casas = pd.read_csv(url)

# Preparando os dados
X = dados_casas[["total_rooms"]].values
y = dados_casas["median_house_value"].values

# Definindo a arquitetura do modelo
modelo_tf = Sequential([
    Dense(10, activation='relu', input_shape=(X.shape[1],)),
    Dense(1)
])

# Compilando o modelo
modelo_tf.compile(optimizer='adam', loss='mse')

# Treinando o modelo
modelo_tf.fit(X, y, epochs=10, batch_size=32)

# Fazendo previsões
y_pred_tf = modelo_tf.predict(X)
d_tf = modelo_tf.predict(X)
Epoch 1/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 7s 1ms/step - loss: 54861455360.0000  
Epoch 2/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 829us/step - loss: 47372525568.0000
Epoch 3/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 940us/step - loss: 37677514752.0000
Epoch 4/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 767us/step - loss: 31218110464.0000
Epoch 5/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 834us/step - loss: 28638320640.0000
Epoch 6/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 752us/step - loss: 28072214528.0000
Epoch 7/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - loss: 27703418880.0000
Epoch 8/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - loss: 27821633536.0000  
Epoch 9/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - loss: 27955210240.0000
Epoch 10/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - loss: 27295885312.0000
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 961us/step
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 828us/step

Neste exemplo, utilizamos `tensorflow.keras` para construir e treinar uma rede neural simples com uma camada densa (`Dense`). O modelo foi treinado para prever os preços das casas com base na variável `total_rooms` (número total de cômodos). Durante o treinamento, a rede neural ajusta os pesos das conexões para minimizar a função de perda (`loss`), que nesse caso foi definida como o erro quadrático médio (`mse`).

Após o treinamento, usamos o modelo para fazer previsões sobre os dados. No entanto, uma rede neural simples como essa pode ser propensa ao overfitting, especialmente se a arquitetura não for devidamente regularizada ou se o conjunto de dados for limitado.

Para mitigar o overfitting, podemos utilizar técnicas de regularização, como o `Dropout`, que desativa aleatoriamente uma fração das unidades durante o treinamento, obrigando a rede a não depender excessivamente de nenhuma unidade específica. Além disso, a escolha de hiperparâmetros, como o número de neurônios, a taxa de aprendizado (`learning_rate`), e o número de épocas (`epochs`), deve ser cuidadosamente ajustada para equilibrar a capacidade de aprendizado e a generalização do modelo.

A seguir, demonstramos como modificar o modelo original para incluir a camada de Dropout, que ajudará a prevenir o overfitting:

In [15]:
from tensorflow.keras.layers import Dropout

# Modificação da arquitetura do modelo para incluir Dropout
modelo_tf = Sequential([
    Dense(10, activation='relu', input_shape=(X.shape[1],)),
    Dropout(0.2),  # 20% das unidades serão desligadas durante o treinamento
    Dense(1)
])

# Compilando o modelo
modelo_tf.compile(optimizer='adam', loss='mse')

# Treinar o modelo com a nova arquitetura
modelo_tf.fit(X, y, epochs=10, batch_size=32)
Epoch 1/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 2s 853us/step - loss: 55741886464.0000
Epoch 2/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 855us/step - loss: 52463255552.0000
Epoch 3/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 865us/step - loss: 43733110784.0000
Epoch 4/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 881us/step - loss: 36213907456.0000
Epoch 5/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 875us/step - loss: 32650985472.0000
Epoch 6/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 819us/step - loss: 30091835392.0000
Epoch 7/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 906us/step - loss: 30268745728.0000
Epoch 8/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 792us/step - loss: 29770106880.0000
Epoch 9/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 860us/step - loss: 29637726208.0000
Epoch 10/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 782us/step - loss: 30105524224.0000
Out[15]:
<keras.src.callbacks.history.History at 0x1bfc68852b0>

A adição da camada de Dropout no modelo foi essencial para mitigar o risco de overfitting durante o treinamento. Os resultados mostraram uma redução constante na perda ao longo das épocas, indicando que o modelo foi capaz de aprender de maneira controlada. Essa técnica, junto com a otimização dos hiperparâmetros, é crucial para garantir que redes neurais sejam capazes de fazer previsões precisas e confiáveis, mesmo em cenários complexos.


© Copyright 2024 | Luciano Magalhães
In [ ]: